//
//  LCSwipeTableViewCell.m
//  LCLibrary
//
//  Created by cc on 14-11-5.
//  Copyright (c) 2014年 cc. All rights reserved.
//

#import "LCSwipeTableViewCell.h"
#import "LCCellUtilityButtonView.h"
#import "LCSwipeCellScrollView.h"
#import "LCCellLongPressGestureRecognizer.h"

#import "LCUtilityButtonTapGestureRecognizer.h"

static NSString * const kTableViewCellContentView = @"UITableViewCellContentView";

#define kSectionIndexWidth 15
#define kAccessoryTrailingSpace 15
#define kLongPressMinimumDuration 0.16f

@interface LCSwipeTableViewCell () <UIScrollViewDelegate,  UIGestureRecognizerDelegate>

@property (nonatomic, weak) UITableView *containingTableView;
@property (nonatomic, assign) LCSwipeTableViewCellState cellState;
@property (nonatomic, assign) CGFloat additionalRightPadding;

@property (nonatomic, strong) UIScrollView *cellScrollView;//cell上添加scrollview
@property (nonatomic, strong) LCCellUtilityButtonView *leftUtilityButtonsView, *rightUtilityButtonsView;//左右按钮视图
@property (nonatomic, strong) UIView *leftUtilityClipView, *rightUtilityClipView;
@property (nonatomic, strong) NSLayoutConstraint *leftUtilityClipConstraint, *rightUtilityClipConstraint;//约束

@property (nonatomic, strong) UILongPressGestureRecognizer *longPressGestureRecognizer;//长按手势
@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer;//点击手势
@property (nonatomic, strong) UIPanGestureRecognizer *tableViewPanGestureRecognizer;//滑动手势
@end


@implementation LCSwipeTableViewCell {
    UIView *_contentCellView;
}

#pragma mark Initializers

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    
    if (self)
    {
        //初始化
        [self initializer];
    }
    
    return self;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    
    if (self)
    {
        //初始化
        [self initializer];
    }
    
    return self;
}

- (void)initializer
{
    //初始化scrollview
    self.cellScrollView = [[LCSwipeCellScrollView alloc] init];
    self.cellScrollView.translatesAutoresizingMaskIntoConstraints = NO;
    self.cellScrollView.delegate = self;
    self.cellScrollView.showsHorizontalScrollIndicator = NO;
    self.cellScrollView.scrollsToTop = NO;
    self.cellScrollView.scrollEnabled = YES;
    
    _contentCellView = [[UIView alloc] init];
    [self.cellScrollView addSubview:_contentCellView];
    
    //添加scrollview到最上层
    UIView *contentViewParent = self;
    UIView *clipViewParent = self.cellScrollView;
    if (![NSStringFromClass([[self.subviews objectAtIndex:0] class]) isEqualToString:kTableViewCellContentView])
    {
        // iOS 7
        contentViewParent = [self.subviews objectAtIndex:0];
        clipViewParent = self;
    }
    NSArray *cellSubviews = [contentViewParent subviews];
    [self insertSubview:self.cellScrollView atIndex:0];
    for (UIView *subview in cellSubviews)
    {
        [_contentCellView addSubview:subview];
    }
    
    //添加约束，上下左右伸缩
    [self addConstraints:@[
                           [NSLayoutConstraint constraintWithItem:self.cellScrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
                           [NSLayoutConstraint constraintWithItem:self.cellScrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],
                           [NSLayoutConstraint constraintWithItem:self.cellScrollView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0],
                           [NSLayoutConstraint constraintWithItem:self.cellScrollView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0],
                           ]];
    
    //添加点击手势
    self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollViewTapped:)];
    self.tapGestureRecognizer.cancelsTouchesInView = NO;
    self.tapGestureRecognizer.delegate = self;
    [self.cellScrollView addGestureRecognizer:self.tapGestureRecognizer];
    
    //添加长按手势
    self.longPressGestureRecognizer = [[LCCellLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(scrollViewPressed:)];
    self.longPressGestureRecognizer.cancelsTouchesInView = NO;
    self.longPressGestureRecognizer.minimumPressDuration = kLongPressMinimumDuration;
    self.longPressGestureRecognizer.delegate = self;
    [self.cellScrollView addGestureRecognizer:self.longPressGestureRecognizer];
    
    //添加左右按钮视图
    self.leftUtilityClipView = [[UIView alloc] init];
    self.leftUtilityClipConstraint = [NSLayoutConstraint constraintWithItem:self.leftUtilityClipView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0];
    self.leftUtilityButtonsView = [[LCCellUtilityButtonView alloc] initWithUtilityButtons:nil
                                                                           parentCell:self
                                                                utilityButtonSelector:@selector(leftUtilityButtonHandler:)];
    
    self.rightUtilityClipView = [[UIView alloc] initWithFrame:self.bounds];
    self.rightUtilityClipConstraint = [NSLayoutConstraint constraintWithItem:self.rightUtilityClipView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0];
    self.rightUtilityButtonsView = [[LCCellUtilityButtonView alloc] initWithUtilityButtons:nil
                                                                            parentCell:self
                                                                 utilityButtonSelector:@selector(rightUtilityButtonHandler:)];
    
    
    UIView *clipViews[] = {self.rightUtilityClipView, self.leftUtilityClipView};
    NSLayoutConstraint *clipConstraints[] = { self.rightUtilityClipConstraint, self.leftUtilityClipConstraint};
    UIView *buttonViews[] = {self.rightUtilityButtonsView, self.leftUtilityButtonsView};
    NSLayoutAttribute alignmentAttributes[] = {NSLayoutAttributeRight, NSLayoutAttributeLeft};
    
    //添加约束
    for (NSUInteger i = 0; i < 2; ++i)
    {
        UIView *clipView = clipViews[i];
        NSLayoutConstraint *clipConstraint = clipConstraints[i];
        UIView *buttonView = buttonViews[i];
        NSLayoutAttribute alignmentAttribute = alignmentAttributes[i];
        clipConstraint.priority = UILayoutPriorityDefaultHigh;
        clipView.translatesAutoresizingMaskIntoConstraints = NO;
        clipView.clipsToBounds = YES;
        [clipViewParent addSubview:clipView];
        [self addConstraints:@[
                               [NSLayoutConstraint constraintWithItem:clipView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
                               [NSLayoutConstraint constraintWithItem:clipView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],
                               [NSLayoutConstraint constraintWithItem:clipView attribute:alignmentAttribute relatedBy:NSLayoutRelationEqual toItem:self attribute:alignmentAttribute multiplier:1.0 constant:0.0],
                               clipConstraint,
                               ]];
        
        [clipView addSubview:buttonView];
        [self addConstraints:@[
                               [NSLayoutConstraint constraintWithItem:buttonView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:clipView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
                               [NSLayoutConstraint constraintWithItem:buttonView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:clipView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],
                               [NSLayoutConstraint constraintWithItem:buttonView attribute:alignmentAttribute relatedBy:NSLayoutRelationEqual toItem:clipView attribute:alignmentAttribute multiplier:1.0 constant:0.0],
                               [NSLayoutConstraint constraintWithItem:buttonView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.contentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:-kUtilityButtonWidthDefault],
                               ]];
    }
}

static NSString * const kTableViewPanState = @"state";

- (void)removeOldTableViewPanObserver
{
    [_tableViewPanGestureRecognizer removeObserver:self forKeyPath:kTableViewPanState];
}

- (void)dealloc
{
    [self removeOldTableViewPanObserver];
}

- (void)setContainingTableView:(UITableView *)containingTableView
{
    [self removeOldTableViewPanObserver];
    
    _tableViewPanGestureRecognizer = containingTableView.panGestureRecognizer;
    
    _containingTableView = containingTableView;
    
    if (containingTableView)
    {
        // Check if the UITableView will display Indices on the right. If that's the case, add a padding
        if ([_containingTableView.dataSource respondsToSelector:@selector(sectionIndexTitlesForTableView:)])
        {
            NSArray *indices = [_containingTableView.dataSource sectionIndexTitlesForTableView:_containingTableView];
            self.additionalRightPadding = indices == nil ? 0 : kSectionIndexWidth;
        }
        
        _containingTableView.directionalLockEnabled = YES;
        
        [self.tapGestureRecognizer requireGestureRecognizerToFail:_containingTableView.panGestureRecognizer];
        
        [_tableViewPanGestureRecognizer addObserver:self forKeyPath:kTableViewPanState options:0 context:nil];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:kTableViewPanState] && object == _tableViewPanGestureRecognizer)
    {
        if(_tableViewPanGestureRecognizer.state == UIGestureRecognizerStateBegan)
        {
            CGPoint locationInTableView = [_tableViewPanGestureRecognizer locationInView:_containingTableView];
            
            BOOL inCurrentCell = CGRectContainsPoint(self.frame, locationInTableView);
            if(!inCurrentCell && _cellState != kCellStateCenter)
            {
                if ([self.delegate respondsToSelector:@selector(tableViewCellShouldHideUtilityButtonsOnSwipe:)])
                {
                    if([self.delegate tableViewCellShouldHideUtilityButtonsOnSwipe:self])
                    {
                        [self hideUtilityButtonsAnimated:YES];
                    }
                }
            }
        }
    }
}

#pragma mark - setters
- (void)setLeftUtilityButtons:(NSArray *)leftUtilityButtons
{
    if (![_leftUtilityButtons isEqualToButtons:leftUtilityButtons]) {
        _leftUtilityButtons = leftUtilityButtons;
        
        self.leftUtilityButtonsView.utilityButtons = leftUtilityButtons;
        
        [self.leftUtilityButtonsView layoutIfNeeded];
        [self layoutIfNeeded];
    }
}

- (void)setLeftUtilityButtons:(NSArray *)leftUtilityButtons buttonWidth:(CGFloat)width
{
    _leftUtilityButtons = leftUtilityButtons;
    
    [self.leftUtilityButtonsView setUtilityButtons:leftUtilityButtons buttonWidth:width];
    
    [self.leftUtilityButtonsView layoutIfNeeded];
    [self layoutIfNeeded];
}

- (void)setRightUtilityButtons:(NSArray *)rightUtilityButtons
{
    if (![_rightUtilityButtons isEqualToButtons:rightUtilityButtons]) {
        _rightUtilityButtons = rightUtilityButtons;
        
        self.rightUtilityButtonsView.utilityButtons = rightUtilityButtons;
        
        [self.rightUtilityButtonsView layoutIfNeeded];
        [self layoutIfNeeded];
    }
}

- (void)setRightUtilityButtons:(NSArray *)rightUtilityButtons buttonWidth:(CGFloat)width
{
    _rightUtilityButtons = rightUtilityButtons;
    
    [self.rightUtilityButtonsView setUtilityButtons:rightUtilityButtons buttonWidth:width];
    
    [self.rightUtilityButtonsView layoutIfNeeded];
    [self layoutIfNeeded];
}

#pragma mark - UITableViewCell overrides

- (void)didMoveToSuperview
{
    self.containingTableView = nil;
    UIView *view = self.superview;
    
    do {
        if ([view isKindOfClass:[UITableView class]])
        {
            self.containingTableView = (UITableView *)view;
            break;
        }
    } while ((view = view.superview));
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    // Offset the contentView origin so that it appears correctly w/rt the enclosing scroll view (to which we moved it).
    CGRect frame = self.contentView.frame;
    frame.origin.x = [self leftUtilityButtonsWidth];
    _contentCellView.frame = frame;
    
    self.cellScrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame) + [self utilityButtonsPadding], CGRectGetHeight(self.frame));
    
    if (!self.cellScrollView.isTracking && !self.cellScrollView.isDecelerating)
    {
        self.cellScrollView.contentOffset = [self contentOffsetForCellState:_cellState];
    }
    
    [self updateCellState];
}

- (void)setFrame:(CGRect)frame
{
    // Fix for new screen sizes
    // Initially, the cell is still 320 points wide
    // We need to layout our subviews again when this changes so our constraints clip to the right width
    BOOL widthChanged = (self.frame.size.width != frame.size.width);
    
    [super setFrame:frame];
    
    if (widthChanged)
        [self layoutIfNeeded];
}

- (void)prepareForReuse
{
    [super prepareForReuse];
    
    [self hideUtilityButtonsAnimated:NO];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    // Work around stupid background-destroying override magic that UITableView seems to perform on contained buttons.
    
    [self.leftUtilityButtonsView pushBackgroundColors];
    [self.rightUtilityButtonsView pushBackgroundColors];
    
    [super setSelected:selected animated:animated];
    
    [self.leftUtilityButtonsView popBackgroundColors];
    [self.rightUtilityButtonsView popBackgroundColors];
}

- (void)didTransitionToState:(UITableViewCellStateMask)state {
    [super didTransitionToState:state];
    
    if (state == UITableViewCellStateDefaultMask) {
        [self layoutSubviews];
    }
}

#pragma mark - Selection handling

- (BOOL)shouldHighlight
{
    BOOL shouldHighlight = YES;
    
    if ([self.containingTableView.delegate respondsToSelector:@selector(tableView:shouldHighlightRowAtIndexPath:)])
    {
        NSIndexPath *cellIndexPath = [self.containingTableView indexPathForCell:self];
        
        shouldHighlight = [self.containingTableView.delegate tableView:self.containingTableView shouldHighlightRowAtIndexPath:cellIndexPath];
    }
    
    return shouldHighlight;
}

- (void)scrollViewPressed:(UIGestureRecognizer *)gestureRecognizer
{
    if ([_delegate respondsToSelector:@selector(tableViewCellDidLongPressed:)]) {
        [_delegate tableViewCellDidLongPressed:self];
    }
    
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan && !self.isHighlighted && self.shouldHighlight)
    {
        [self setHighlighted:YES animated:NO];
    }
    
    else if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
    {
        // Cell is already highlighted; clearing it temporarily seems to address visual anomaly.
        [self setHighlighted:NO animated:NO];
        [self scrollViewTapped:gestureRecognizer];
    }
    
    else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled)
    {
        [self setHighlighted:NO animated:NO];
    }
}

- (void)scrollViewTapped:(UIGestureRecognizer *)gestureRecognizer
{
    if (_cellState == kCellStateCenter)
    {
//        if (self.isSelected)
//        {
//            [self deselectCell];
//        }
//        else
            if (self.shouldHighlight) // UITableView refuses selection if highlight is also refused.
        {
            [self selectCell];
        }
    }
    else
    {
        // Scroll back to center
        [self hideUtilityButtonsAnimated:YES];
    }
}

- (void)selectCell
{
    if (_cellState == kCellStateCenter)
    {
        NSIndexPath *cellIndexPath = [self.containingTableView indexPathForCell:self];
        
        if ([self.containingTableView.delegate respondsToSelector:@selector(tableView:willSelectRowAtIndexPath:)])
        {
            cellIndexPath = [self.containingTableView.delegate tableView:self.containingTableView willSelectRowAtIndexPath:cellIndexPath];
        }
        
        if (cellIndexPath)
        {
            [self.containingTableView selectRowAtIndexPath:cellIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
            
            if ([self.containingTableView.delegate respondsToSelector:@selector(tableView:didSelectRowAtIndexPath:)])
            {
                [self.containingTableView.delegate tableView:self.containingTableView didSelectRowAtIndexPath:cellIndexPath];
            }
        }
    }
}

- (void)deselectCell
{
    if (_cellState == kCellStateCenter)
    {
        NSIndexPath *cellIndexPath = [self.containingTableView indexPathForCell:self];
        
        if ([self.containingTableView.delegate respondsToSelector:@selector(tableView:willDeselectRowAtIndexPath:)])
        {
            cellIndexPath = [self.containingTableView.delegate tableView:self.containingTableView willDeselectRowAtIndexPath:cellIndexPath];
        }
        
        if (cellIndexPath)
        {
            [self.containingTableView deselectRowAtIndexPath:cellIndexPath animated:NO];
            
            if ([self.containingTableView.delegate respondsToSelector:@selector(tableView:didDeselectRowAtIndexPath:)])
            {
                [self.containingTableView.delegate tableView:self.containingTableView didDeselectRowAtIndexPath:cellIndexPath];
            }
        }
    }
}

#pragma mark - Utility buttons handling

- (void)rightUtilityButtonHandler:(id)sender
{
    LCUtilityButtonTapGestureRecognizer *utilityButtonTapGestureRecognizer = (LCUtilityButtonTapGestureRecognizer *)sender;
    NSUInteger utilityButtonIndex = utilityButtonTapGestureRecognizer.buttonIndex;
    if ([self.delegate respondsToSelector:@selector(tableViewCell:didTriggerRightUtilityButtonWithIndex:)])
    {
        [self.delegate tableViewCell:self didTriggerRightUtilityButtonWithIndex:utilityButtonIndex];
    }
}

- (void)leftUtilityButtonHandler:(id)sender
{
    LCUtilityButtonTapGestureRecognizer *utilityButtonTapGestureRecognizer = (LCUtilityButtonTapGestureRecognizer *)sender;
    NSUInteger utilityButtonIndex = utilityButtonTapGestureRecognizer.buttonIndex;
    if ([self.delegate respondsToSelector:@selector(tableViewCell:didTriggerLeftUtilityButtonWithIndex:)])
    {
        [self.delegate tableViewCell:self didTriggerLeftUtilityButtonWithIndex:utilityButtonIndex];
    }
}

- (void)hideUtilityButtonsAnimated:(BOOL)animated
{
    if (_cellState != kCellStateCenter)
    {
        [self.cellScrollView setContentOffset:[self contentOffsetForCellState:kCellStateCenter] animated:animated];
        
        if ([self.delegate respondsToSelector:@selector(tableViewCell:scrollingToState:)])
        {
            [self.delegate tableViewCell:self scrollingToState:kCellStateCenter];
        }
    }
}

- (void)showLeftUtilityButtonsAnimated:(BOOL)animated {
    if (_cellState != kCellStateLeft)
    {
        [self.cellScrollView setContentOffset:[self contentOffsetForCellState:kCellStateLeft] animated:animated];
        
        if ([self.delegate respondsToSelector:@selector(tableViewCell:scrollingToState:)])
        {
            [self.delegate tableViewCell:self scrollingToState:kCellStateLeft];
        }
    }
}

- (void)showRightUtilityButtonsAnimated:(BOOL)animated {
    if (_cellState != kCellStateRight)
    {
        [self.cellScrollView setContentOffset:[self contentOffsetForCellState:kCellStateRight] animated:animated];
        
        if ([self.delegate respondsToSelector:@selector(tableViewCell:scrollingToState:)])
        {
            [self.delegate tableViewCell:self scrollingToState:kCellStateRight];
        }
    }
}

- (BOOL)isUtilityButtonsHidden {
    return _cellState == kCellStateCenter;
}


#pragma mark - Geometry helpers

- (CGFloat)leftUtilityButtonsWidth
{
#if CGFLOAT_IS_DOUBLE
    return round(CGRectGetWidth(self.leftUtilityButtonsView.frame));
#else
    return roundf(CGRectGetWidth(self.leftUtilityButtonsView.frame));
#endif
}

- (CGFloat)rightUtilityButtonsWidth
{
#if CGFLOAT_IS_DOUBLE
    return round(CGRectGetWidth(self.rightUtilityButtonsView.frame) + self.additionalRightPadding);
#else
    return roundf(CGRectGetWidth(self.rightUtilityButtonsView.frame) + self.additionalRightPadding);
#endif
}

- (CGFloat)utilityButtonsPadding
{
#if CGFLOAT_IS_DOUBLE
    return round([self leftUtilityButtonsWidth] + [self rightUtilityButtonsWidth]);
#else
    return roundf([self leftUtilityButtonsWidth] + [self rightUtilityButtonsWidth]);
#endif
}

- (CGPoint)contentOffsetForCellState:(LCSwipeTableViewCellState)state
{
    CGPoint scrollPt = CGPointZero;
    
    switch (state)
    {
        case kCellStateCenter:
            scrollPt.x = [self leftUtilityButtonsWidth];
            break;
            
        case kCellStateRight:
            scrollPt.x = [self utilityButtonsPadding];
            break;
            
        case kCellStateLeft:
            scrollPt.x = 0;
            break;
    }
    
    return scrollPt;
}

- (void)updateCellState
{
    // Update the cell state according to the current scroll view contentOffset.
    for (NSNumber *numState in @[
                                 @(kCellStateCenter),
                                 @(kCellStateLeft),
                                 @(kCellStateRight),
                                 ])
    {
        LCSwipeTableViewCellState cellState = numState.integerValue;
        
        if (CGPointEqualToPoint(self.cellScrollView.contentOffset, [self contentOffsetForCellState:cellState]))
        {
            _cellState = cellState;
            break;
        }
    }
    
    // Update the clipping on the utility button views according to the current position.
    CGRect frame = [self.contentView.superview convertRect:self.contentView.frame toView:self];
    frame.size.width = CGRectGetWidth(self.frame);
    
    self.leftUtilityClipConstraint.constant = MAX(0, CGRectGetMinX(frame) - CGRectGetMinX(self.frame));
    self.rightUtilityClipConstraint.constant = MIN(0, CGRectGetMaxX(frame) - CGRectGetMaxX(self.frame));
    
    if (self.isEditing) {
        self.leftUtilityClipConstraint.constant = 0;
        self.cellScrollView.contentOffset = CGPointMake([self leftUtilityButtonsWidth], 0);
        _cellState = kCellStateCenter;
    }
    
    self.leftUtilityClipView.hidden = (self.leftUtilityClipConstraint.constant == 0);
    self.rightUtilityClipView.hidden = (self.rightUtilityClipConstraint.constant == 0);
    
    if (self.accessoryType != UITableViewCellAccessoryNone && !self.editing) {
        UIView *accessory = [self.cellScrollView.superview.subviews lastObject];
        
        CGRect accessoryFrame = accessory.frame;
        accessoryFrame.origin.x = CGRectGetWidth(frame) - CGRectGetWidth(accessoryFrame) - kAccessoryTrailingSpace + CGRectGetMinX(frame);
        accessory.frame = accessoryFrame;
    }
    
    // Enable or disable the gesture recognizers according to the current mode.
    if (!self.cellScrollView.isDragging && !self.cellScrollView.isDecelerating)
    {
        self.tapGestureRecognizer.enabled = YES;
//        self.longPressGestureRecognizer.enabled = (_cellState == kCellStateCenter);
    }
    else
    {
        self.tapGestureRecognizer.enabled = NO;
//        self.longPressGestureRecognizer.enabled = NO;
    }
    
    self.cellScrollView.scrollEnabled = !self.isEditing;
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    if (velocity.x >= 0.5f)
    {
        if (_cellState == kCellStateLeft || !self.rightUtilityButtons || self.rightUtilityButtonsWidth == 0.0)
        {
            _cellState = kCellStateCenter;
        }
        else
        {
            _cellState = kCellStateRight;
        }
    }
    else if (velocity.x <= -0.5f)
    {
        if (_cellState == kCellStateRight || !self.leftUtilityButtons || self.leftUtilityButtonsWidth == 0.0)
        {
            _cellState = kCellStateCenter;
        }
        else
        {
            _cellState = kCellStateLeft;
        }
    }
    else
    {
        CGFloat leftThreshold = [self contentOffsetForCellState:kCellStateLeft].x + (self.leftUtilityButtonsWidth / 2);
        CGFloat rightThreshold = [self contentOffsetForCellState:kCellStateRight].x - (self.rightUtilityButtonsWidth / 2);
        
        if (targetContentOffset->x > rightThreshold)
        {
            _cellState = kCellStateRight;
        }
        else if (targetContentOffset->x < leftThreshold)
        {
            _cellState = kCellStateLeft;
        }
        else
        {
            _cellState = kCellStateCenter;
        }
    }
    
    if ([self.delegate respondsToSelector:@selector(tableViewCell:scrollingToState:)])
    {
        [self.delegate tableViewCell:self scrollingToState:_cellState];
    }
    
    if (_cellState != kCellStateCenter)
    {
        if ([self.delegate respondsToSelector:@selector(tableViewCellShouldHideUtilityButtonsOnSwipe:)])
        {
            for (LCSwipeTableViewCell *cell in [self.containingTableView visibleCells])
            {
                if (cell != self && [cell isKindOfClass:[LCSwipeTableViewCell class]] && [self.delegate tableViewCellShouldHideUtilityButtonsOnSwipe:cell]) {
                    [cell hideUtilityButtonsAnimated:YES];
                }
            }
        }
    }
    
    *targetContentOffset = [self contentOffsetForCellState:_cellState];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView.contentOffset.x > [self leftUtilityButtonsWidth])
    {
        if ([self rightUtilityButtonsWidth] > 0)
        {
            if (self.delegate && [self.delegate respondsToSelector:@selector(tableViewCell:canSwipeToState:)])
            {
                BOOL shouldScroll = [self.delegate tableViewCell:self canSwipeToState:kCellStateRight];
                if (!shouldScroll)
                {
                    scrollView.contentOffset = CGPointMake([self leftUtilityButtonsWidth], 0);
                }
            }
        }
        else
        {
            [scrollView setContentOffset:CGPointMake([self leftUtilityButtonsWidth], 0)];
            self.tapGestureRecognizer.enabled = YES;
        }
    }
    else
    {
        // Expose the left button view
        if ([self leftUtilityButtonsWidth] > 0)
        {
            if (self.delegate && [self.delegate respondsToSelector:@selector(tableViewCell:canSwipeToState:)])
            {
                BOOL shouldScroll = [self.delegate tableViewCell:self canSwipeToState:kCellStateLeft];
                if (!shouldScroll)
                {
                    scrollView.contentOffset = CGPointMake([self leftUtilityButtonsWidth], 0);
                }
            }
        }
        else
        {
            [scrollView setContentOffset:CGPointMake(0, 0)];
            self.tapGestureRecognizer.enabled = YES;
        }
    }
    
    [self updateCellState];
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self updateCellState];
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(tableViewCellDidEndScrolling:)]) {
        [self.delegate tableViewCellDidEndScrolling:self];
    }
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    [self updateCellState];
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(tableViewCellDidEndScrolling:)]) {
        [self.delegate tableViewCellDidEndScrolling:self];
    }
}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        self.tapGestureRecognizer.enabled = YES;
    }
    
}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ((gestureRecognizer == self.containingTableView.panGestureRecognizer && otherGestureRecognizer == self.longPressGestureRecognizer)
        || (gestureRecognizer == self.longPressGestureRecognizer && otherGestureRecognizer == self.containingTableView.panGestureRecognizer))
    {
        // Return YES so the pan gesture of the containing table view is not cancelled by the long press recognizer
        return YES;
    }
    else
    {
        return NO;
    }
}

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ![touch.view isKindOfClass:[UIControl class]];
}

@end
